package pers.zb.center.web.boss.activemq.listener;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import pers.zb.center.common.core.enums.SeparatorEnum;
import pers.zb.center.web.boss.socket.notice.permission.update.handler.PermissionUpdateNoticeWebSocketHandler;


/**
 * 权限变更消息监听
 */
public class PermissionJmsListener implements MessageListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(PermissionJmsListener.class);

    @Value("#{configProperties['zb.app.code']}")
    private String zbAppCode;//当前应用的编码，比如 zb-ucenter-web

    //权限更新，socket通知标识符
    public static final String PERMISSION_UPDATE_KEY = "permission_update";
    public static final String PERMISSION_UPDATE_SEPARATOR = SeparatorEnum.PERMISSION_UPDATE.getType();
    
    @Override
    public void onMessage(Message message) {
        String msgText = null;
        try {
            msgText = ((javax.jms.TextMessage) message).getText();//接收到消息内容
        } catch (JMSException e) {
            LOGGER.error("Jms illegal message!");
        }
        
        /**
         * 如果对于井号分割的不太明白的，可以去看为何要要分割，分别代表什么意思？  
         *      所在类方法：TopicMessageServiceImpl.sendPermissionUpdateMessage()
         *      找到 session.createTextMessage 代码，会看到，井号前面是应用编码，后面是被更新权限的角色名称
         */
        if(msgText == null || msgText.split(PERMISSION_UPDATE_SEPARATOR).length < 2){
            return;
        }
        /**
         * 刷新权限缓存
         * 
         * 【问题】：
         *      假如N个用户登录了zb-ucenter-web系统，且用户的角色尽不相同(比如员工角色、经理角色等)，
         *      如果管理员只更新了员工角色的权限，那么如何保证角色为员工的用户权限更新，而经理角色的权限不进行更新操作？
         * 【实现】：
         *      当然，实现方式肯定不止一种，这里我说一下我的实现思路吧，需要结合socket推送服务：
         *      1、每个应用都配置了一个权限变更的消息监听服务，详情请见 /resources/application/activemq/spring-activemq.xml ，里面有Listener的监听器配置，应用启动的时候，会监听对应的消息队列。
         *      2、每个用户登录系统之后，会连接权限变更的socket服务
         *      3、假如管理员更新了zb-ucenter-web应用的员工角色的权限，发送了一条权限变更的MQ消息到permission_zb-ucenter-web队列中
         *      4、zb-ucenter-web应用监听到了队列有消息过来，则会执行对应的监听器方法
         *      5、解析出消息内容后，发送socket消息给对应的权限变更socket服务，让socket推送给在线登录的用户
         *      6、当客户端收到socket推送通知的时候，会主动请求后台提供的权限变更的controller，实现当前用户的权限变更（当然后台在处理的时候，肯定要判断是否与变更的角色一致）
         *      
         *      以上便是我的实现思路，MQ发送消息到队列，应用监听队列并获取消息，发送socket通知到推送服务，socket通知所有在线用户权限变更，客户端主动请求刷新权限缓存。
         */
        
        final String appCode = msgText.split(PERMISSION_UPDATE_SEPARATOR)[0];//获取应用编码
        final String roleName = msgText.split(PERMISSION_UPDATE_SEPARATOR)[1];//获取被更新的角色名称
        if (zbAppCode.equals(appCode)) {//判断当前应用的编码，是否与消息内容中的编码一致。
            
            //通过socket服务，通知对应角色的登录用户，让客户端主动请求刷新权限缓存的接口，刷新缓存
            new PermissionUpdateNoticeWebSocketHandler().sendMessageToAllUser(
                    new org.springframework.web.socket.TextMessage(PERMISSION_UPDATE_KEY + PERMISSION_UPDATE_SEPARATOR + roleName));
            
            
            
            
            /**
             * 下面这种方式不可取。MyCasRealm.clearAuthz()方法中，是对当前登录用户进行权限的更新，无法做到对其他登录用户的权限刷新。
             * 所以，要想实现对应角色的所有登录用户的权限刷新，就需要通知所有该角色的用户，让客户端主动请求后台提供的刷新权限的接口，只有这样，系统才会确定知道当前登录用户是谁了。
             */
            /**
                RealmSecurityManager rsm = (RealmSecurityManager)SecurityUtils.getSecurityManager();  
                MyCasRealm realm = (MyCasRealm)rsm.getRealms().iterator().next();  
                realm.clearAuthz();
            */
            
            
            
            LOGGER.info("PermissionJmsListener ---- 成功通知appCode为：{}的应用更新权限，被更新权限的角色名称:{}", appCode,roleName);
        }
    }
}
